/*
 * Copyright Notice. Copyright 2011 Northwestern University and Stanford
 * University (“caBIG® Participant”). AIM Template Enterprise Service conforms
 * to caBIG® technical specifications and is part of the caBIG® initiative. The
 * software subject to this notice and license includes human readable source
 * code form, machine readable, binary, object code form and related
 * documentation (the “caBIG® Software”).
 *
 * This caBIG® Software License (the “License”) is between the National Cancer
 * Institute (NCI) and You. “You (or “Your”) shall mean a person or an entity,
 * and all other entities that control, are controlled by, or are under common
 * control with the entity. “Control” for purposes of this definition means (i)
 * the direct or indirect power to cause the direction or management of such
 * entity, whether by contract or otherwise, or (ii) ownership of fifty percent
 * (50%) or more of the outstanding shares, or (iii) beneficial ownership of
 * such entity.
 *
 * Provided that You agree to the conditions described below, NCI grants You a
 * non-exclusive, worldwide, perpetual, fully-paid-up, no-charge, irrevocable,
 * transferable and royalty-free right and license in its rights in the caBIG®
 * Software, including any copyright or patent rights therein, to (i) use,
 * install, disclose, access, operate, execute, reproduce, copy, modify,
 * translate, market, publicly display, publicly perform, and prepare
 * derivative works of the caBIG® Software in any manner and for any purpose,
 * and to have or permit others to do so; (ii) make, have made, use, practice,
 * sell, and offer for sale, import, and/or otherwise dispose of caBIG®
 * Software (or portions thereof); (iii) distribute and have distributed to and
 * by third parties the caBIG® Software and any modifications and derivative
 * works thereof; and (iv) sublicense the foregoing rights set out in (i), (ii)
 * and (iii) to third parties, including the right to license such rights to
 * further third parties. For sake of clarity, and not by way of limitation,
 * NCI shall have no right of accounting or right of payment from You or Your
 * sublicensees for the rights granted under this License. This License is
 * granted at no charge to You. Your downloading, copying, modifying,
 * displaying, distributing or use of caBIG® Software constitutes acceptance of
 * all of the terms and conditions of this Agreement. If you do not agree to
 * such terms and conditions, you have no right to download, copy, modify,
 * display, distribute or use the caBIG® Software.
 *
 * Your redistributions of the source code for the caBIG® Software must retain
 * the above copyright notice, this list of conditions and the disclaimer and
 * limitation of liability of Article 6 below. Your redistributions in object
 * code form must reproduce the above copyright notice, this list of conditions
 * and the disclaimer of Article 6 in the documentation and/or other materials
 * provided with the distribution, if any.
 *
 * Your end-user documentation included with the redistribution, if any, must
 * include the following acknowledgment: “This product includes software
 * developed by Danny Korenblum, Alan Snyder, Vitaliy Semeshko, Vladimir Kleper
 * and Pattanasak Mongkolwat, Northwestern University and Stanford University.”
 * If You do not include such end-user documentation, You shall include this
 * acknowledgment in the caBIG® Software itself, wherever such third-party
 * acknowledgments normally appear.
 *
 * You may not use the names “Northwestern University”, “Stanford University”,
 * “The National Cancer Institute”, “NCI”, “Cancer Bioinformatics Grid” or
 * “caBIG®” to endorse or promote products derived from this caBIG® Software.
 * This License does not authorize You to use any trademarks, service marks,
 * trade names, logos or product names of either caBIG® Participant, NCI or
 * caBIG®, except as required to comply with the terms of this License.
 *
 * For sake of clarity, and not by way of limitation, You are not prohibited by
 * this License from incorporating this caBIG® Software into Your proprietary
 * programs and into any third party proprietary programs. However, if You
 * incorporate the caBIG® Software into third party proprietary programs, You
 * agree that You are solely responsible for obtaining any permission from such
 * third parties required to incorporate the caBIG® Software into such third
 * party proprietary programs and for informing Your sublicensees, including
 * without limitation Your end-users, of their obligation to secure any
 * required permissions from such third parties before incorporating the caBIG®
 * Software into such third party proprietary software programs. In the event
 * that You fail to obtain such permissions, You agree to indemnify NCI for any
 * claims against NCI by such third parties, except to the extent prohibited by
 * law, resulting from Your failure to obtain such permissions.
 * For sake of clarity, and not by way of limitation, You may add Your own
 * copyright statement to Your modifications and to the derivative works, and
 * You may provide additional or different license terms and conditions in
 * Your sublicenses of modifications of the caBIG® Software, or any derivative
 * works of the caBIG® Software as a whole, provided Your use, reproduction,
 * and distribution of the Work otherwise complies with the conditions stated
 * in this License.
 *
 * THIS caBIG® SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE) ARE
 * DISCLAIMED. IN NO EVENT SHALL NCI OR THE NORTHWESTERN UNIVERSITY OR ITS
 * AFFILIATES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS caBIG® SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package edu.stanford.isis.atb.ui.view.widget.splitpane;

import java.awt.Component;
import java.awt.Cursor;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicSplitPaneDivider;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import edu.stanford.isis.atb.system.exception.ATBException;
import edu.stanford.isis.atb.ui.view.resources.MiscImageBundle;

/**
 * @author Vitaliy Semeshko
 */
public class CollapsibleSplitPane extends JSplitPane {

	private static final Logger logger = LoggerFactory.getLogger(CollapsibleSplitPane.class);

	private static final MiscImageBundle images = MiscImageBundle.getInstance();

	private static final Icon leftDefaultIcon = images.getSplitPaneLeftDefaultIcon().loadIcon();
	private static final Icon leftHoverIcon = images.getSplitPaneLeftHoverIcon().loadIcon();
	private static final Icon rightDefaultIcon = images.getSplitPaneRightDefaultIcon().loadIcon();
	private static final Icon rightHoverIcon = images.getSplitPaneRightHoverIcon().loadIcon();
	
	private static final Icon topDefaultIcon = images.getSplitPaneTopDefaultIcon().loadIcon();
	private static final Icon topHoverIcon = images.getSplitPaneTopHoverIcon().loadIcon();
	private static final Icon bottomDefaultIcon = images.getSplitPaneBottomDefaultIcon().loadIcon();
	private static final Icon bottomHoverIcon = images.getSplitPaneBottomHoverIcon().loadIcon();

	private BasicSplitPaneDivider dividerContainer;

	private boolean initialized;

	private boolean manuallyCollapsed;
	
	private CollapseMode mode;

	public static enum CollapseMode {
		COLLAPSE_LEFT,
		COLLAPSE_RIGHT,
		COLLAPSE_TOP,
		COLLAPSE_BOTTOM;
	}
	
    public CollapsibleSplitPane() {}

    public CollapsibleSplitPane(int newOrientation) {
        super(newOrientation);
    }
	
	public void setCollapsible(CollapseMode mode) {
		if (initialized) {
			throw new ATBException("Collapsible split pane already initialized.");
		}

		this.mode = mode;
		
		for (Component component : getComponents()) {
			if (component instanceof BasicSplitPaneDivider) {
				dividerContainer = (BasicSplitPaneDivider) component;
				break;
			}
		}

		if (dividerContainer == null) {
			logger.warn("Can't initialize collapsible split pane. No BasicSplitPaneDivider found.");
			return;
		}

		setOneTouchExpandable(true);

		JButton left = (JButton) dividerContainer.getComponent(0);
		JButton right = (JButton) dividerContainer.getComponent(1);

		final CollapseButton button = new CollapseButton(left.getActionListeners(), right.getActionListeners());

		setOneTouchExpandable(false);

		dividerContainer.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
		dividerContainer.setLayout(new GridBagLayout());

		dividerContainer.add(button);

		addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, new PropertyChangeListener() {
			@Override
			public void propertyChange(PropertyChangeEvent pce) {
				button.update();
			}
		});
		
		initialized = true;
	}

	public boolean isManuallyCollapsed() {
		return manuallyCollapsed;
	}
	
	public boolean isCollapsed() {
		if (mode == null) {
			return false;
		}
		
		Insets insets = getInsets();
		int currentLoc = getUI().getDividerLocation(this);
		
		if (mode == CollapseMode.COLLAPSE_LEFT || mode == CollapseMode.COLLAPSE_TOP) {
			if (orientation == JSplitPane.HORIZONTAL_SPLIT) {
				if (currentLoc == insets.left) {
					return true;
				} else {
					return false;
				}
			} else {
				if (currentLoc == insets.top) {
					return true;
		        } else {
					return false;
		        }
			}
		} else {
			if (orientation == JSplitPane.HORIZONTAL_SPLIT) {
				if (currentLoc >= (getWidth() - insets.right - dividerContainer.getWidth())) {
					return true;
				} else {
					return false;
				}
			} else {
				if (currentLoc >= (getHeight() - insets.bottom - dividerContainer.getHeight())) {
					return true;
	            } else {
	            	return false;
	            }
			}
		}
	}
	
	/**
	 * @author Vitaliy Semeshko
	 */
	private class CollapseButton extends JButton {

		public CollapseButton(final ActionListener[] collapseLeftActionListeners, 
				final ActionListener[] collapseRightActionListeners) {
			setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
			setBorder(BorderFactory.createEmptyBorder());
			setFocusable(false);
			setOpaque(false);
			setRolloverEnabled(true);
			setContentAreaFilled(false);

			switch (mode) {
			case COLLAPSE_LEFT:
				setIcon(leftDefaultIcon);
				setRolloverIcon(leftHoverIcon);
				break;
			case COLLAPSE_RIGHT:
				setIcon(rightDefaultIcon);
				setRolloverIcon(rightHoverIcon);
				break;
			case COLLAPSE_TOP:
				setIcon(topDefaultIcon);
				setRolloverIcon(topHoverIcon);
				break;
			case COLLAPSE_BOTTOM:
				setIcon(bottomDefaultIcon);
				setRolloverIcon(bottomHoverIcon);
				break;
			}
			
			addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					
					manuallyCollapsed = !isCollapsed();
					
					if (leftDirectionAllowed() || topDirectionAllowed()) {
						for (ActionListener listener : collapseLeftActionListeners) {
							listener.actionPerformed(e);
						}
					} else {
						for (ActionListener listener : collapseRightActionListeners) {
							listener.actionPerformed(e);
						}
					}
					update();
				}
			});	
		}

		public void update() {
			SwingUtilities.invokeLater(new Runnable() {
				@Override
				public void run() {
					switch (mode) {
					case COLLAPSE_LEFT:
					case COLLAPSE_RIGHT:
						if (leftDirectionAllowed()) {
							setIcon(leftDefaultIcon);
							setRolloverIcon(leftHoverIcon);
						} else {
							setIcon(rightDefaultIcon);
							setRolloverIcon(rightHoverIcon);
						}
						break;
					case COLLAPSE_TOP:
					case COLLAPSE_BOTTOM:
						if (topDirectionAllowed()) {
							setIcon(topDefaultIcon);
							setRolloverIcon(topHoverIcon);
						} else {
							setIcon(bottomDefaultIcon);
							setRolloverIcon(bottomHoverIcon);
						}
						break;
					}
				}
			});
		}

		private boolean leftDirectionAllowed() {
			boolean isCollapsed = isCollapsed(); 
			return ((!isCollapsed && mode == CollapseMode.COLLAPSE_LEFT) ||
					(isCollapsed && mode == CollapseMode.COLLAPSE_RIGHT));
		}
		
		private boolean topDirectionAllowed() {
			boolean isCollapsed = isCollapsed(); 
			return ((!isCollapsed && mode == CollapseMode.COLLAPSE_TOP) ||
					(isCollapsed && mode == CollapseMode.COLLAPSE_BOTTOM));
		}

	}

}
